<?php


namespace common\service;

use common\model\DelayOrderTaskModel;
use common\model\EntityModel;
use common\model\ProduceStatementConfigModel;
use common\model\ProjectModel;
use common\model\TaskModel;
use support\SingletonTrait;


class ProduceStatementReportService
{
    use SingletonTrait;

    /**
     * 报表详情
     * @param $projectId
     * @param $month
     * @param $tenantId
     * @return array
     */
    public function detail($projectId, $month, $tenantId)
    {
        $projectData = model(ProjectModel::class)->where(['id' => $projectId])->find();
        if (empty($projectData)) {
            return [];
        }
        $episodeDurationMinutes = ProjectService::getInstance()->getProjectDuration($projectData['duration']);

        // 全部数据统计
        $produceStatementConfigList = model(ProduceStatementConfigModel::class)
            ->where(['project_id' => $projectId, 'tenant_id' => $tenantId])
            ->field("(`inside_cost` + `outside_cost`) as cost,inside_cost,outside_cost,month_time,from_unixtime(month_time,'%Y-%m') as month_time_y_m")
            ->select();
        $episodeData = model(EntityModel::class)
            ->where(['project_id' => $projectId, 'tenant_id' => $tenantId, 'module_id' => module_by_code('episode')['id']])
            ->where("json ->> '$.episode_seal_time' > 0 and json ->> '$.episode_seal_time' <= " . time())
            ->field("count(id) as total,from_unixtime(json ->> '$.episode_seal_time', '%Y-%m') as 'episode_seal_time_ym',count(json ->> '$.episode_is_show' = 'yes' or null) as show_episode_total_num")
            ->group("episode_seal_time_ym")
            ->order('episode_seal_time_ym')
            ->select();
        // 月份封板数量
        $episodeSealData = array_column($episodeData, 'total', 'episode_seal_time_ym');

        $totalCost = 0;
        $nowMonthCost = 0; // 本月总成本
        $lastMonthCost = 0; // 上月总成本
        $nowMonthInsideCost = 0; // 本月内部成本
        $lastMonthInsideCost = 0; // 上月内部成本
        $nowMonthOutsideCost = 0; // 本月外部成本
        $lastMonthOutsideCost = 0; // 上月外部成本
        $projectStartMonth = date('Y-m', $projectData['start_time']);
        $currentMonth = date('Y-m', $month);
        $latestMonth = date('Y-m', strtotime('-1 month', $month));
        $totalMonth = [];
        $endMonth = date('Y-m');
        if (!empty($episodeData)) {
            $projectCurrentMonth = $projectStartMonth = $episodeData[0]['episode_seal_time_ym'];
            $projectInfo['start_time'] = strtotime($episodeData[0]['episode_seal_time_ym']);
        } else {
            $projectCurrentMonth = $projectStartMonth;
            $projectInfo['start_time'] = $projectData['start_time'];
        }
        do {
            $totalMonth[$projectCurrentMonth] = [
                'month_time_y_m' => $projectCurrentMonth,
                'month_time' => strtotime($projectCurrentMonth),
                'minute_cost' => 0,
                'duration' => 0,
                'total' => 0,
            ];
            $projectCurrentMonth = date("Y-m", strtotime($projectCurrentMonth . ' +1 month'));
        } while (strtotime($projectCurrentMonth) <= strtotime($endMonth));
        foreach ($produceStatementConfigList as $item) {
            $item['total'] = $episodeSealData[$item['month_time_y_m']] ?? 0;
            $item['duration'] = $item['total'] * $episodeDurationMinutes;
            $item['minute_cost'] = 0;
            if ($item['duration'] > 0) {
                $item['minute_cost'] = $item['cost'] / $item['duration'];
            }
            // 本月成本
            if (!empty($item['month_time_y_m']) && $item['month_time_y_m'] == $currentMonth) {
                $nowMonthInsideCost = $item['inside_cost'];
                $nowMonthOutsideCost = $item['outside_cost'];
                $nowMonthCost = $item['cost'];
            }
            // 上月成本
            if (!empty($item['month_time_y_m']) && $item['month_time_y_m'] == $latestMonth) {
                $lastMonthInsideCost = $item['inside_cost'];
                $lastMonthOutsideCost = $item['outside_cost'];
                $lastMonthCost = $item['cost'];
            }
            if (isset($totalMonth[$item['month_time_y_m']])) {
                $totalMonth[$item['month_time_y_m']]['minute_cost'] = $item['minute_cost'];
                $totalMonth[$item['month_time_y_m']]['duration'] = $item['duration'];
                $totalMonth[$item['month_time_y_m']]['total'] = $item['total'];
            }
            $totalCost += $item['cost'];
            // 项目立项到现在的数据
            if ($item['month_time_y_m'] >= $projectStartMonth) {
                $totalCost += $item['cost'];
            }
        }

        // 本月交付集数
        $nowMonthEpisodeNum = 0;
        // 上月交付集数
        $lastMonthEpisodeNum = 0;

        $totalEpisode = 0;
        $nowMonthMinutesNum = 0;
        $totalMinutes = 0;
        $showEpisodeTotalMinutes = 0;
        $showEpisodeTotalNum = 0;
        foreach ($episodeData as $item) {
            $item['duration'] = $item['total'] * $episodeDurationMinutes;
            $totalEpisode += $item['total'];
            $showEpisodeTotalNum += $item['show_episode_total_num'];
            $totalMinutes += $item['duration'];

            $item['episode_shot_duration'] = $item['show_episode_total_num'] * $episodeDurationMinutes;
            $showEpisodeTotalMinutes += $item['episode_shot_duration'];
            // 本月交付集数
            if ($item['episode_seal_time_ym'] == $currentMonth) {
                $nowMonthEpisodeNum = $item['total'];
                $nowMonthMinutesNum += $item['duration'];
            }
            // 上月交付集数
            if ($item['episode_seal_time_ym'] == $latestMonth) {
                $lastMonthEpisodeNum = $item['total'];
            }
        }

        // 当前时间
        $projectInfo['now_time'] = time();
        // 本月交付成片月环比 = 本月减去上月除以本月
        $deliveryEpisodeMonthLoopRate = 0;
        if (!empty($nowMonthEpisodeNum) && !empty($lastMonthEpisodeNum)) {
            $deliveryEpisodeMonthLoopRate = ($nowMonthEpisodeNum - $lastMonthEpisodeNum) / $lastMonthEpisodeNum;
        }

        $insideCostLoopRate = 0;
        if (!empty($nowMonthInsideCost) && !empty($lastMonthInsideCost)) {
            $insideCostLoopRate = ($nowMonthInsideCost - $lastMonthInsideCost) / $lastMonthInsideCost;
        }
        $outsideCostLoopRate = 0;
        if (!empty($nowMonthOutsideCost) && !empty($lastMonthOutsideCost)) {
            $outsideCostLoopRate = ($nowMonthOutsideCost - $lastMonthOutsideCost) / $lastMonthOutsideCost;
        }
        $costLoopRate = 0;
        if (!empty($nowMonthCost) && !empty($lastMonthCost)) {
            $costLoopRate = ($nowMonthCost - $lastMonthCost) / $lastMonthCost;
        }

        // 读取上月+前11个月的数据
        $tmpMonth = [];
        $dtStart = strtotime(date('Y-m', strtotime('-11 month', $month)));
        $dtEnd = strtotime(date('Y-m', $month)); // 这里month前端传过来,默认往前推了一个月
        while ($dtStart <= $dtEnd) {
            $dtStart = strtotime('+1 day', $dtStart);
            $tmpMonth[date('Y-m', $dtStart)] = date('Y-m', $dtStart);
        }
        $weekRange = [];
        foreach ($tmpMonth as $month) {
            $weekRange[]['firstday'] = $month;
        }

        $initEpisodeList = [];
        $episodeMap = array_column($episodeData, null, 'episode_seal_time_ym');
        foreach ($weekRange as $item) {
            $initEpisodeList[] = [
                'total' => $episodeMap[$item['firstday']]['total'] ?? 0,
                'episode_seal_time_ym' => $item['firstday'],
                'duration' => $episodeMap[$item['firstday']]['duration'] ?? 0,
            ];
        }
        $nowMonthMinuteCost = 0;
        if ($nowMonthEpisodeNum) {
            $nowMonthMinuteCost = $nowMonthCost / ($nowMonthEpisodeNum * $episodeDurationMinutes);
        }

        $projectDuration = 0;
        if (!empty($totalMinutes) && !empty($totalEpisode)) {
            $projectDuration = $totalMinutes / $totalEpisode;
        }
        return [
            'inside_cost' => $nowMonthInsideCost,  // 本月内部成本
            'outside_cost' => $nowMonthOutsideCost, // 本月外部成本
            'now_month_cost' => $nowMonthCost, // 本月总成本
            'last_month_cost' => $lastMonthCost, // 上月总成本
            'last_month_inside_cost' => $lastMonthInsideCost, // 上月内部成本
            'last_month_outside_cost' => $lastMonthOutsideCost, // 上月外部成本
            'total_cost' => $totalCost, // 总投入
            'all_report_list' => array_values($totalMonth), // 全部数据统计报表
            'episode_list' => $initEpisodeList,
            'total_episode' => $totalEpisode, // 总交付(集)
            'show_episode_total_num' => $showEpisodeTotalNum, // 总交付(集)
            'show_episode_total_minutes' => $showEpisodeTotalMinutes, // 总交付(集总分钟)
            'total_minutes' => $totalMinutes, // 总交付(分钟)
            'now_month_episode_num' => $nowMonthEpisodeNum, // 本月交付(集)
            'now_month_minutes_num' => $nowMonthMinutesNum, // 本月交付(分钟)
            'last_month_episode_num' => $lastMonthEpisodeNum, // 上月交付(集)
            'project_info' => $projectInfo,
            'project_duration' => $projectDuration,
            'delivery_episode_month_loop_rate' => $deliveryEpisodeMonthLoopRate, // 本月交付成片月环比
            'inside_cost_loop_rate' => $insideCostLoopRate, // 本月内部成本环比
            'outside_cost_loop_rate' => $outsideCostLoopRate, // 外包成本环比
            'cost_loop_rate' => $costLoopRate, // 总成本环比
            'now_month_minute_cost' => $nowMonthMinuteCost, // 本月分钟成本
        ];
    }

    /**
     * 管理财务数据
     * @param $data
     * @param $tenantId
     * @return array|bool
     * @throws \Exception
     */
    public function modify($data, $tenantId)
    {
        $where = [
            'project_id' => $data['project_id'],
            'month_time' => $data['month_time'],
            'tenant_id' => $tenantId
        ];
        // 存在就编辑,不存在就新增
        $findData = model(ProduceStatementConfigModel::class)->where($where)->field('id')->find();
        if ($findData) {
            $data['id'] = $findData['id'];
            return model(ProduceStatementConfigModel::class)->modifyItem($data);
        }
        $data['tenant_id'] = $tenantId;
        return model(ProduceStatementConfigModel::class)->addItem($data);
    }


    /**
     * 生产信息简报
     * @param $projectId
     * @param $startTime
     * @param $endTime
     * @return array[]
     */
    public function productionInfoReport($projectId, $startTime, $endTime)
    {
        $field = [
            'task.id as task_id',
            'task.name as task_name',
            'task.plan_start_time',
            'task.plan_end_time',
            'trt.link_id as episode_id',
            'episode.name as episode_name',
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) as task_status"
        ];
        $closedStatusId = StatusService::getInstance()->getTaskDefaultClosedStatus()['id'];
        $productionInfoReportList = model(TaskModel::class)->cache(5)
            ->join("task_relation_tag trt on task.id = trt.task_id and link_module_code = 'episode'")
            ->join("(select id,name from entity) episode on episode.id = trt.link_id")
            ->field($field)
            ->where(['task.step_type' => ['IN', [TaskModel::STEP_TYPE_STANDARD_REVIEW, TaskModel::STEP_TYPE_STANDARD_MEETING]]])
            ->where(['task.project_id' => $projectId])
            ->where([0 => [
                ['task.plan_end_time' => ['EGT', $startTime]],
                ['task.plan_start_time' => ['ELT', $endTime]],
                "_logic" => 'and'
            ]])
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $closedStatusId]])
            ->select();
        if (empty($productionInfoReportList)) {
            return [];
        }
        $taskIds = array_column($productionInfoReportList, 'task_id');

        // 查询加班完成【今日完成,但是任务在推送日报的时候,还未完成】
        $delayOrderTaskList = model(DelayOrderTaskModel::class)
            ->field('task.id as task_id')
            ->join('task on task.id = delay_order_task.task_id')
            ->where(['delay_order_task.type' => 'today_done'])
            ->where(['task.id' => ['IN', $taskIds]])
            ->where(['delay_order_task.original_plan_time' => ['BETWEEN', [$startTime, $endTime]]])
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.`json`,'$.task_status'))" => ['NEQ', $closedStatusId]])
            ->select();

        if (empty($delayOrderTaskList)) {
            $delayOrderTaskList = [];
        }

        $statusList = StatusService::getInstance()->getList([], 'id,name,code,color');
        $statusMap = array_column($statusList, null, 'id');

        return array_map(function ($tmp) use ($delayOrderTaskList, $statusMap) {
            $tmp['overtime'] = 'no';
            if (in_array($tmp['task_id'], $delayOrderTaskList)) {
                $tmp['overtime'] = 'yes';
            }
            $tmp['task_status'] = $statusMap[$tmp['task_status']];
            return $tmp;
        }, $productionInfoReportList);
    }
}